PHP和Python对象中的静态方法,两种不同的世界...?

1 投票
3 回答
541 浏览
提问于 2025-04-16 07:49

我是一名PHP程序员,正在尝试进入Python的世界,但对我来说这非常困难。

在PHP中,静态方法最大的好处就是可以自动创建实例。你不需要在每个文件中都声明对象,如果你只需要用一次,甚至可以用一行代码来传不同的参数。

<?php
class Foo { 
    function __constructor__(){
        $this->var = 'blah';
    }
   public static function aStaticMethod() {
       return $this->var;
   }
}

echo Foo::aStaticMethod();
?>

我们可以从静态方法调用构造函数,对吧?而且我们可以像调用普通方法一样访问类中的所有内容……我们甚至可以在PHP类中有一个静态构造函数,并这样调用它:Object::construct()->myMethod();(这样每次都可以传不同的参数)

但在Python中就不行了吗??@staticmethod让类中的方法变成一个简单的函数,完全看不到任何东西??

class socket(object):

def __init__(self):
    self.oclass = otherclass()
    print 'test' # does this constructor called at all when calling static method??                

@staticmethod
def ping():
    return self.oclass.send('PING') # i can't access anything!!!


print Anidb.ping()

我无法从那个该死的静态方法中访问任何东西,它就像一个独立的函数,或者类似的东西……??

也许我用错了装饰器?也许Python中有类似PHP静态方法的东西?

1) 请告诉我为什么静态方法是孤立的。
2) 请告诉我如何实现和PHP静态方法相同的行为。
3) 如果PHP静态方法的行为不好,请告诉我它的替代实用用法。

附言:我希望所有这些能尽量少写代码。
附附言:对示例代码的详细注释将不胜感激。

谢谢。

3 个回答

3

你需要用到classmethod。这个东西会把类本身作为第一个参数传进去。

编辑:

class C(object):
  foo = 42

  @classmethod
  def printfoo(cls):
    print cls.foo

C.printfoo()
4

在PHP中,静态方法并不像你想的那样,它们不能访问实例成员。也就是说,使用静态方法时不能用到$this

<?php
class Foo {

    public static $var = 'foo ';

    function __construct(){
        echo 'constructing ';
        $this->var = 'blah ';
    }

    public function aMethod() {
        return $this->var;
    }
    public static function aStaticMethod() {
        #return $this->$var;  -> you can't do that,
        # $this can be accessed only in instance methods, not static
        return self::$var;
    }
}

$foo = new Foo();
echo $foo->aMethod();

echo Foo::aStaticMethod();

?>

在Python中,对象有三种方法。静态方法就像是在类外定义的函数,把它放在对象里只是为了和类放在一起,作为辅助函数。方法只能访问类中定义的变量(用@classmethod这个装饰器来标记)。这和PHP中的静态成员或方法差不多。这样的类方法的第一个参数应该是cls,可以通过cls访问类的内容。普通方法的第一个参数必须是self,只有它们能访问实例成员。

如果你想要多个相同类型的对象,肯定需要实例,其他类型的方法并不是你想要的。如果你只有一个对象的实例,可以考虑使用类方法(或者PHP的静态方法)。

不过在大多数情况下,如果你不知道为什么要这样做,就不要去折腾这些,还是用对象的实例和普通方法比较好。否则,你可能会因为引入了很多限制而让你的代码后续出现问题,这种做法叫做过早优化。

2

我看到你已经接受了另一个答案,但我不确定那个答案能否和你的代码一起工作。具体来说,oclass这个变量只会在类的实例中创建,而不是在类本身中。你可以这样做:

class socket(object):
    oclass = otherclass()                

    @classmethod
    def ping(cls):
        return cls.oclass.send('PING')

socket.ping()

不过,如果你使用你现有的代码,并且去掉所有的装饰器,你可以简单地在同一行中创建实例并调用一个方法:

socket().ping()

撰写回答