class Account:
# here is the main class
# a non-static method
def login(self, url, email, password):
# as a convention self is passed as a
# placeholder for the class Object itself
self.login_url = url
self.user_email = email
self.user_password = password
print(login_url, user_email, user_password)
将非静态方法称为静态方法
"""
* Referencing the Account.login(self, url, email, password)
* Just call the `Account` object as the self
"""
Account.login(Account, "https://example.com/login", "email@example.com", "password_example")
:$ https://example.com/login email@example.com password_example
48
也许最简单的选择就是将这些函数放在类之外:
class Dog(object):
def __init__(self, name):
self.name = name
def bark(self):
if self.name == "Doggy":
return barking_sound()
else:
return "yip yip"
def barking_sound():
return "woof woof"
# garden.py
def trim(a):
pass
def strip(a):
pass
def bunch(a, b):
pass
def _foo(foo):
pass
class powertools(object):
"""
Provides much regarded gardening power tools.
"""
@staticmethod
def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
return 42
@staticmethod
def random():
return 13
@staticmethod
def promise():
return True
def _bar(baz, quux):
pass
class _Dice(object):
pass
class _6d(_Dice):
pass
class _12d(_Dice):
pass
class _Smarter:
pass
class _MagicalPonies:
pass
class _Samurai:
pass
class Foo(_6d, _Samurai):
pass
class Bar(_12d, _Smarter, _MagicalPonies):
pass
...
# tests.py
import unittest
import garden
class GardenTests(unittest.TestCase):
pass
class PowertoolsTests(unittest.TestCase):
pass
class FooTests(unittest.TestCase):
pass
class BarTests(unittest.TestCase):
pass
...
# interactive.py
from garden import trim, bunch, Foo
f = trim(Foo())
bunch(f, Foo())
...
# my_garden.py
import garden
from garden import powertools
class _Cowboy(garden._Samurai):
def hit():
return powertools.promise() and powertools.random() or 0
class Foo(_Cowboy, garden.Foo):
pass
class Dog:
count = 0 # this is a class variable
dogs = [] # this is a class variable
def __init__(self, name):
self.name = name #self.name is an instance variable
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n): # this is an instance method
print("{} says: {}".format(self.name, "woof! " * n))
def rollCall(n): #this is implicitly a class method (see comments below)
print("There are {} dogs.".format(Dog.count))
if n >= len(Dog.dogs) or n < 0:
print("They are:")
for dog in Dog.dogs:
print(" {}".format(dog))
else:
print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
class Dog:
count = 0 # this is a class variable
dogs = [] # this is a class variable
def __init__(self, name):
self.name = name #self.name is an instance variable
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n): # this is an instance method
print("{} says: {}".format(self.name, "woof! " * n))
@staticmethod
def rollCall(n):
print("There are {} dogs.".format(Dog.count))
if n >= len(Dog.dogs) or n < 0:
print("They are:")
for dog in Dog.dogs:
print(" {}".format(dog))
else:
print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)
9 回答
是的,可以像这样创建静态方法(虽然使用下划线代替CamelCase方法更多Pythonic):
以上使用装饰器语法 . 这个语法相当于
这可以像你描述的那样使用:
静态方法的内置示例是Python 3中的
str.maketrans()
,它是Python 2中string
模块中的一个函数 .可以在描述时使用的另一个选项是
classmethod
,区别在于classmethod将类作为隐式的第一个参数获取,如果是子类,则它将子类作为隐式的第一个参数 .请注意,
cls
不是第一个参数的必需名称,但是如果您使用其他任何东西,大多数有经验的Python编码器都会认为它很糟糕 .这些通常用作替代构造函数 .
内置示例是
dict.fromkeys()
:是的,使用staticmethod装饰器
请注意,某些代码可能使用定义静态方法的旧方法,使用
staticmethod
作为函数而不是装饰器 . 只有在你必须支持古老版本的Python(2.2和2.3)时才应该使用它这与第一个示例(使用
@staticmethod
)完全相同,只是没有使用漂亮的装饰器语法最后,谨慎使用staticmethod()!在Python中很少需要使用静态方法,并且我已经看到它们多次使用,其中单独的"top-level"函数会更清晰 .
The following is verbatim from the documentation::
在Python 3中:
使用非静态方法是另一个好处,因为它们是静态方法 .
将非静态方法称为静态方法
也许最简单的选择就是将这些函数放在类之外:
使用此方法,可以在类中保留修改或使用内部对象状态(具有副作用)的函数,并且可以将可重用的实用程序函数移出到外部 .
假设这个文件名为
dogs.py
. 要使用这些,您需要调用dogs.barking_sound()
而不是dogs.Dog.barking_sound
.如果您确实需要静态方法作为类的一部分,则可以使用staticmethod装饰器 .
是的,看看staticmethod装饰者:
除了static method objects行为的特殊性之外,在组织模块级代码时,您可以使用它们获得某种美感 .
...
...
...
它现在变得更加直观和自我记录,其中某些组件应该被使用,并且它理想地用于命名不同的测试用例,并且具有直接的方法来测试模块如何映射到纯粹主义者测试下的实际模块 .
我经常发现应用这种方法来组织项目的实用程序代码是可行的 . 很多时候,人们立即赶紧创建一个包装,最终得到9个模块,其中一个模块有120个LOC,剩下的最多只有24个 . 我更喜欢从这开始并将其转换为包并仅为真正值得它们的野兽创建模块:
你真的不需要使用
@staticmethod
装饰器 . 只是声明一个方法(不期望self参数)并从类中调用它 . 装饰器只是为了你想要能够从一个实例调用它(这不是你想要做的)大多数情况下,你只是使用功能...
我不时遇到这个问题 . 我喜欢的用例和例子是:
创建类cmath的对象没有意义,因为cmath对象中没有状态 . 但是,cmath是一些方法的集合,它们都以某种方式相关 . 在上面的例子中,cmath中的所有函数都以某种方式处理复数 .
我认为Steven is actually right . 要回答原始问题,那么,为了 Build 一个类方法,简单地假设第一个参数不是一个调用实例,然后确保你只从类中调用该方法 .
(注意,这个答案指的是Python 3.x.在Python 2.x中,你将得到
TypeError
来调用类本身的方法 . )例如:
在此代码中,“rollCall”方法假定第一个参数不是实例(如果它是由实例而不是类调用的话) . 只要从类而不是实例调用“rollCall”,代码就可以正常工作 . 如果我们尝试从一个实例调用“rollCall”,例如:
但是,它会引发异常,因为它会发送两个参数:本身和-1,而“rollCall”只定义为接受一个参数 .
顺便说一下,rex.rollCall()会发送正确数量的参数,但也会引发异常,因为当函数期望n为数字时,n表示一个Dog实例(即rex) .
这就是装饰的用武之地:如果我们在“rollCall”方法之前使用
然后,通过明确声明该方法是静态的,我们甚至可以从实例中调用它 . 现在,
会工作 . 然后,在方法定义之前插入@staticmethod会阻止实例将自身作为参数发送 .
您可以通过在注释掉@staticmethod行的情况下尝试以下代码来验证这一点 .