class Anc:
@classmethod
def format(cls, msg):
"I dont need an instance to work"
print(f"\n{cls}.format({msg.upper()})")
def __init__(self, keep=1) -> None:
self.keep = keep
def format_instance(self, msg):
"I do and it allows me to use configuration stored in it"
print(f"\n{self}.format_instance({msg[:self.keep]=})")
@classmethod
def create_me(cls, *args, **kwargs):
""" a factory is the main reason for class methods """
return cls(*args, **kwargs)
class Child1(Anc):
@classmethod
def format(cls, msg):
print(f"\n{cls}.format({msg.lower()})")
@staticmethod
def format_static(msg):
print(f"\nLonely static without cls or instance 😭{msg}😭")
class Child2(Anc):
def format_instance(self, msg):
"replace with stars"
print(f"\n{self}.format_instance({'*' * len(msg)})")
def wannabe_method(self, msg):
"is this a function or a method?"
print(f"\nwannabe_method({self},{msg=}).")
def wont_work_as_method():
"too many arguments when called as method"
print(f"\nwont_work_as_method()")
Anc.format("calling format as a classmethod. No instance needed!")
anc = Anc(keep=2)
anc.format("calling format through an instance. It'll automatically get the class as first argument!")
Child1.format("calling Child1's format, which does lower")
Child2.format("calling Child2's format, which will up on Anc.format")
Child1.format_static("this is a static")
child1 = Child1(keep=3)
child1.format_instance("this message will get truncated...")
child2 = Child2()
try:
child2.added_method("hey just got added!")
except (AttributeError,) as e:
print(f"\n❌as expected this fails {e} cuz missing method")
Child2.added_method = wannabe_method
child2.added_method("hey just got added! self gets the instance magically")
try:
wannabe_method("nope not gonna work")
except (TypeError,) as e:
print(f"\n❌as expected this fails {e} because it only got 1 argument")
wannabe_method("FAKE INSTANCE!", "hackish work")
Child2.wont_work = wont_work_as_method
try:
child2.wont_work()
except (TypeError,) as e:
print(f"\n❌ oh no! no place for self {e}")
child2_through_factory = Child2.create_me()
child2_through_factory.format_instance("My God, it's full of stars")
child2_through_factory.format("to uppercase")
child1_through_factory = Child1.create_me()
child1_through_factory.format("TO LOWERCASE")
输出:
<class '__main__.Anc'>.format(CALLING FORMAT AS A CLASSMETHOD. NO INSTANCE NEEDED!)
<class '__main__.Anc'>.format(CALLING FORMAT THROUGH AN INSTANCE. IT'LL AUTOMATICALLY GET THE CLASS AS FIRST ARGUMENT!)
<class '__main__.Child1'>.format(calling child1's format, which does lower)
<class '__main__.Child2'>.format(CALLING CHILD2'S FORMAT, WHICH WILL UP ON ANC.FORMAT)
Lonely static without cls or instance 😭this is a static😭
<__main__.Child1 object at 0x10a824460>.format_instance(msg[:self.keep]='thi')
❌as expected this fails 'Child2' object has no attribute 'added_method' cuz missing method
wannabe_method(<__main__.Child2 object at 0x10a824280>,msg='hey just got added! self gets the instance magically').
❌as expected this fails wannabe_method() missing 1 required positional argument: 'msg' because it only got 1 argument
wannabe_method(FAKE INSTANCE!,msg='hackish work').
❌ oh no! no place for self wont_work_as_method() takes 0 positional arguments but 1 was given
<__main__.Child2 object at 0x10a824220>.format_instance(**************************)
<class '__main__.Child2'>.format(TO UPPERCASE)
<class '__main__.Child1'>.format(to lowercase)
3条答案
按热度按时间mum43rcc1#
他们错了。但是,这是他们犯的一个小错误,而且做视频课程,包括说话和打字,肯定是有挑战性的。没什么大不了的。
当函数属于一个类时,它是一个方法(一种更特殊的函数形式);当它在类之外时,它是一个函数。
我怎么知道他们错了?
在Python中可以使用以下语法创建一个:
这不是
@classfunction
装饰器,这是@classmethod
装饰器。请参阅www.example.com上的文档https://docs.python.org/3/library/functions.html#classmethod
g6ll5ycj2#
方法是类中函数的正确术语。方法和函数非常相似。唯一的区别是方法是用对象调用的,并且可以修改对象的数据。函数可以修改和返回数据,但它们对对象没有影响。
编辑:类函数和方法的意思是一样的,尽管说类函数不是正确的表达方式。
myss37ts3#
你不需要用类方法创建一个示例。格式化程序.format(“foo”)vs格式化程序().format(“foo”)。
这也意味着你不能在示例上存储状态/配置,因为没有示例。继承和多态性也可能不适用于类方法--也就是说,如果我打算在类方法上使用它们,我会对实际行为非常谨慎。
在实践中,你通常希望使用常规方法,* 除了创建示例的类方法 *(通常被称为 * 工厂方法 *)。如果你真的不需要示例,也许一个独立的函数也可以完成这项工作。Python不要求函数只存在于类上(像Java)。
至于术语,除了考试的考虑之外,不要担心它。方法和函数没有什么不同,除了一个有一个示例(或@classmethod中的类)作为第一个参数。
通常,如果它缩进在
class XXX:
声明下,我就调用一个方法,如果它是独立的,我就调用一个函数。好的,如果你不介意有点困惑,请继续阅读......
除此之外,所有这些东西之间的区别在实践中是相当不稳定的。类方法可以从示例调用,函数可以动态地添加到类中...
这里有一些有趣的东西,大部分是好奇心,除了
create_me
classmethod,它是使用classmethod作为工厂的主要原因,但是它显示了边界是不固定的。这不是您通常想要做的事情,但它确实介绍了类上的方法/函数如何行为的一些细微区别。
输出: